home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / xv.c < prev    next >
C/C++ Source or Header  |  1992-01-02  |  55KB  |  1,951 lines

  1. /*
  2.  * xv.c - main section of xv.  X setup, window creation, etc.
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  *
  7.  *  Contains:
  8.  *            int  main(argc,argv)
  9.  *     static void Syntax()
  10.  *     static int  openPic(filenum)
  11.  *     static void closePic()
  12.  *     static void OpenFirstPic()
  13.  *     static void OpenNextPic()
  14.  *     static void OpenNextQuit()
  15.  *     static void OpenNextLoop()
  16.  *     static void OpenPrevPic()
  17.  *     static void OpenNamedPic()
  18.  *     static void MainLoop()
  19.  *     static void CreateMainWindow(geom, name)
  20.  *            void FixAspect(grow, w, h)
  21.  *     static void MakeDispNames()
  22.  *     static void stickInList();
  23.  *            void DeleteCmd();
  24.  *            int  rd_int(name)
  25.  *            int  rd_str(name)
  26.  *            int  rd_flag(name)
  27.  */
  28.  
  29.  
  30. /*
  31.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  32.  *                       The University of Pennsylvania
  33.  *
  34.  * Permission to use, copy, and distribute for non-commercial purposes,
  35.  * is hereby granted without fee, providing that the above copyright
  36.  * notice appear in all copies and that both the copyright notice and this
  37.  * permission notice appear in supporting documentation. 
  38.  *
  39.  * The software may be modified for your own purposes, but modified versions
  40.  * may not be distributed.
  41.  *
  42.  * This software is provided "as is" without any expressed or implied warranty.
  43.  *
  44.  * The author may be contacted via:
  45.  *    US Mail:   John Bradley
  46.  *               GRASP Lab, Room 301C
  47.  *               3401 Walnut St.  
  48.  *               Philadelphia, PA  19104
  49.  *
  50.  *    Phone:     (215) 898-8813
  51.  *    EMail:     bradley@cis.upenn.edu       
  52.  */
  53.  
  54.  
  55. #define MAIN
  56. #define NEEDSTIME
  57. #define NEEDSDIR     /* for value of MAXPATHLEN */
  58.  
  59. #include "xv.h"
  60. #include "bitmaps.h"
  61. #include "sunras.h"
  62.  
  63. #include <X11/Xatom.h>
  64.  
  65.  
  66. /* program needs one of the following fonts.  Trys them in ascending order */
  67.  
  68. #define FONT1 "-*-lucida-medium-r-*-*-12-*"
  69. #define FONT2 "-*-helvetica-medium-r-*-*-12-*"
  70. #define FONT3 "-*-helvetica-medium-r-*-*-11-*"
  71. #define FONT4 "6x13"
  72. #define FONT5 "fixed"
  73.  
  74. /* a mono-spaced font needed for the 'pixel value tracking' feature */
  75. #define MFONT1 "-misc-fixed-medium-r-normal-*-13-*"
  76. #define MFONT2 "6x13"   
  77. #define MFONT3 "-*-courier-medium-r-*-*-12-*"
  78. #define MFONT4 "fixed"   
  79.  
  80.  
  81. /* file types that can be read */
  82. #define UNKNOWN 0
  83. #define GIF     1
  84. #define PM      2
  85. #define PBM     3
  86. #define XBM     4
  87. #define SUNRAS  5
  88.  
  89. #ifdef HAVE_JPEG
  90. #define JFIF    6
  91. #endif
  92.  
  93.  
  94. static int    keeparound = 0;   /* don't quit after deleting last image */
  95. static int    autoquit = 0;     /* quit after loading first pic to rootW */
  96. static int    autosmooth = 0;   /* smooth picture upon loading */
  97. static int    autodither = 0;   /* colordither picture upon loading */
  98. static float  expand = 1.0;     /* '-expand' argument */
  99. static char  *maingeom = NULL;
  100. static char   initpath[MAXPATHLEN];
  101. static Atom   __SWM_VROOT = None;
  102.  
  103. /* used in DeleteCmd() */
  104. static char  **mainargv;
  105. static int     mainargc;
  106.  
  107.  
  108. /* local function pre-definitions */
  109. #ifdef __STDC__
  110. static void Syntax(void);
  111. static void RmodeSyntax(void);
  112. static int  openPic(int);
  113. static void closePic(void);
  114. static void OpenFirstPic(void);
  115. static void OpenNextPic(void);
  116. static void OpenNextQuit(void);
  117. static void OpenNextLoop(void);
  118. static void OpenPrevPic(void);
  119. static void OpenNamedPic(void);
  120. static void MainLoop(void);
  121. static void CreateMainWindow(char *, char *);
  122. static void MakeDispNames(void);
  123. static void stickInList(void);
  124. static int  argcmp(char *, char *, int);
  125. #else
  126. static void Syntax(), RmodeSyntax(), closePic(), OpenFirstPic(), OpenNextPic();
  127. static void OpenNextQuit(), OpenNextLoop(), OpenPrevPic(), OpenNamedPic();
  128. static void MainLoop(), CreateMainWindow(), MakeDispNames(), stickInList();
  129. static int  openPic(), argcmp();
  130. #endif
  131.  
  132.  
  133. /*******************************************/
  134. int main(argc, argv)
  135. int   argc;
  136. char *argv[];
  137. /*******************************************/
  138. {
  139.   int   i, imap, ctrlmap, gmap, clrroot, nopos, limit2x;
  140.   char *display, *whitestr, *blackstr, *histr, *lostr,
  141.        *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom;
  142.   char *rootfgstr, *rootbgstr, *visualstr;
  143.   int  curstype, stdinflag;
  144.   u_long fgRGB, bgRGB;
  145.  
  146.   XColor ecdef;
  147.   Window rootReturn, parentReturn, *children;
  148.   unsigned int numChildren;
  149.  
  150.  
  151.   /*****************************************************/
  152.   /*** variable Initialization                       ***/
  153.   /*****************************************************/
  154.  
  155.   GETWD(initpath);
  156.   mainargv = argv;
  157.   mainargc = argc;
  158.  
  159.   /* init internal variables */
  160.   display = NULL;
  161.   fgstr = bgstr = rootfgstr = rootbgstr = NULL;
  162.   histr = lostr = whitestr = blackstr = NULL;
  163.   visualstr = NULL;
  164.   pic = epic = cpic = NULL;
  165.   theImage = NULL;
  166.   LocalCmap = 0;
  167.   stdinflag = 0;
  168.  
  169.  
  170.   /* init default colors */
  171.   fgstr = "#000000";  bgstr = "#98C0D0";
  172.   histr = "#AECEEF";  lostr = "#608090";
  173.  
  174.   
  175.   cmd = rindex(argv[0],'/');
  176.   if (!cmd) cmd = argv[0]; else cmd++;
  177.  
  178.   /* init command-line options flags */
  179.   infogeom = DEFINFOGEOM;  ctrlgeom = DEFCTRLGEOM;  
  180.   gamgeom  = DEFGAMGEOM;
  181.  
  182.   ncols = -1;  noglob = 0;  mono = 0;  
  183.   perfect = 0;  ninstall = 0;  fixedaspect = 0;
  184.   DEBUG = 0;  bwidth = 2;
  185.   useroot = clrroot = noqcheck = rwcolor = owncmap = 0;
  186.   waitsec = -1;  waitloop = 0;  automax = 0;
  187.   rootMode = 0;  hsvmode = 0;
  188.   nopos = limit2x = 0;
  189.   curstype = XC_crosshair;
  190.  
  191.   defaspect = normaspect = 1.0;
  192.   mainW = dirW = infoW = ctrlW = gamW = psW = (Window) NULL;
  193. #ifdef HAVE_JPEG
  194.   jpegW = (Window) NULL;
  195. #endif
  196.   imap = ctrlmap = gmap = 0;
  197.  
  198.   ch_offx = ch_offy = p_offx = p_offy = 0;
  199.  
  200.   /* init info box variables */
  201.   infoUp = 0;
  202.   infoMode = INF_STR;
  203.   for (i=0; i<NISTR; i++) SetISTR(i,"");
  204.  
  205.   /* init ctrl box variables */
  206.   ctrlUp = 0;
  207.   curname = 0;
  208.   formatStr[0] ='\0';
  209.  
  210.   gamUp = 0;
  211.  
  212.   Init24to8();
  213.  
  214.   /*****************************************************/
  215.   /*** X Resource Initialization                     ***/
  216.   /*****************************************************/
  217.  
  218.   /* once through the argument list to find the display name, if any */
  219.   for (i=1; i<argc; i++) {
  220.     if (!strncmp(argv[i],"-help",5)) {     /* help */
  221.       Syntax();
  222.       exit(0);
  223.     }
  224.  
  225.     else if (!strncmp(argv[i],"-d",2)) {  /* display */
  226.       i++;
  227.       if (i<argc) display = argv[i];
  228.       break;
  229.     }
  230.   }
  231.  
  232.   /* open the display */
  233.   if ( (theDisp=XOpenDisplay(display)) == NULL) {
  234.     fprintf(stderr, "%s: Can't open display\n",argv[0]);
  235.     exit(1);
  236.   }
  237.  
  238.  
  239.  
  240.   if (rd_str ("aspect")) {
  241.     int n,d;
  242.     if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1)
  243.       fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd);
  244.     else defaspect = (float) n / (float) d;
  245.   }
  246.       
  247.   if (rd_flag("2xlimit"))        limit2x     = def_int;      
  248.   if (rd_flag("autoDither"))     autodither  = def_int;
  249.   if (rd_flag("autoSmooth"))     autosmooth  = def_int;
  250.   if (rd_str ("background"))     bgstr       = def_str;
  251.   if (rd_str ("black"))          blackstr    = def_str;
  252.   if (rd_int ("borderWidth"))    bwidth      = def_int;
  253.   if (rd_str ("ctrlGeometry"))   ctrlgeom    = def_str;
  254.   if (rd_flag("ctrlMap"))        ctrlmap     = def_int;
  255.   if (rd_int ("cursor"))         curstype    = def_int;
  256.   if (rd_str ("expand"))         expand      = atof(def_str);
  257.   if (rd_flag("fixed"))          fixedaspect = def_int;
  258.   if (rd_str ("foreground"))     fgstr       = def_str;
  259.   if (rd_str ("geometry"))       maingeom    = def_str;
  260.   if (rd_str ("ceditGeometry"))  gamgeom     = def_str;
  261.   if (rd_flag("ceditMap"))       gmap        = def_int;
  262.   if (rd_flag("hsvMode"))        hsvmode     = def_int;
  263.   if (rd_str ("highlight"))      histr       = def_str;
  264.   if (rd_str ("infoGeometry"))   infogeom    = def_str;
  265.   if (rd_flag("infoMap"))        imap        = def_int;
  266.   if (rd_flag("keepAround"))     keeparound  = def_int;
  267.   if (rd_str ("lowlight"))       lostr       = def_str;
  268.   if (rd_flag("mono"))           mono        = def_int;
  269.   if (rd_int ("ncols"))        { ncols = def_int; if (ncols>=0) noglob = 1; }
  270.   if (rd_flag("nglobal"))        noglob      = def_int;
  271.   if (rd_flag("ninstall"))       ninstall    = def_int;
  272.   if (rd_flag("nopos"))          nopos       = def_int;
  273.   if (rd_flag("noqcheck"))       noqcheck    = def_int;
  274.   if (rd_flag("ownCmap"))        owncmap     = def_int;
  275.   if (rd_flag("perfect"))        perfect     = def_int;
  276.   if (rd_str ("rootBackground")) rootbgstr   = def_str;
  277.   if (rd_str ("rootForeground")) rootfgstr   = def_str;
  278.   if (rd_int ("rootMode"))       rootMode    = def_int;
  279.   if (rd_flag("rwColor"))        rwcolor     = def_int;
  280.   if (rd_flag("slow24"))         slow24      = def_int;
  281.   if (rd_str ("visual"))         visualstr   = def_str;
  282.   if (rd_str ("white"))          whitestr    = def_str;
  283.       
  284.  
  285.   /*****************************************************/
  286.   /*** Command Line Options                          ***/
  287.   /*****************************************************/
  288.   
  289.   for (i=1, numnames=0; i<argc; i++) {
  290.     if (argv[i][0] != '-') {           /* a file name.  put it in list */
  291.       if (numnames<MAXNAMES) {
  292.     namelist[numnames++] = argv[i];
  293.     if (numnames==MAXNAMES) {
  294.       fprintf(stderr,"%s: too many filenames.  Only using first %d.\n",
  295.           cmd, MAXNAMES);
  296.     }
  297.       }
  298.     }
  299.  
  300.     else if (!strcmp(argv[i],  "-"))           /* stdin flag */
  301.       stdinflag++;
  302.  
  303.     else if (!argcmp(argv[i],"-2xlimit",2))    /* 2xlimit */
  304.       limit2x = !limit2x;
  305.  
  306.     else if (!argcmp(argv[i],"-aspect",2)) {   /* default aspect */
  307.       int n,d;
  308.       if (++i<argc) {
  309.     if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1)
  310.       fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]);
  311.     else defaspect = (float) n / (float) d;
  312.       }
  313.     }
  314.  
  315.     else if (!argcmp(argv[i],"-bg",3))        /* background color */
  316.       { if (++i<argc) bgstr = argv[i]; }
  317.  
  318.     else if (!argcmp(argv[i],"-black",3))     /* black color */
  319.       { if (++i<argc) blackstr = argv[i]; }
  320.     
  321.     else if (!argcmp(argv[i],"-bw",3))        /* border width */
  322.       { if (++i<argc) bwidth=atoi(argv[i]); }
  323.  
  324.     else if (!argcmp(argv[i],"-cegeometry",4))    /* gammageom */
  325.       { if (++i<argc) gamgeom = argv[i]; }
  326.     
  327.     else if (!argcmp(argv[i],"-cemap",4))    /* gmap */
  328.       gmap++;
  329.     
  330.     else if (!argcmp(argv[i],"-cgeometry",3))    /* ctrlgeom */
  331.       { if (++i<argc) ctrlgeom = argv[i]; }
  332.     
  333.     else if (!argcmp(argv[i],"-clear",3))    /* clear */
  334.       clrroot++;
  335.     
  336.     else if (!argcmp(argv[i],"-cmap",3))    /* ctrlmap */
  337.       ctrlmap++;
  338.     
  339.     else if (!argcmp(argv[i],"-cursor",3))    /* cursor */
  340.       { if (++i<argc) curstype = atoi(argv[i]); }
  341.  
  342.     else if (!argcmp(argv[i],"-DEBUG",2))     /* debug */
  343.       { if (++i<argc) DEBUG = atoi(argv[i]); }
  344.  
  345.     else if (!argcmp(argv[i],"-display",3))     /* display */
  346.       { if (++i<argc) display = argv[i]; }
  347.  
  348.     else if (!argcmp(argv[i],"-dither",3))      /* autodither */
  349.       autodither = !autodither;
  350.  
  351.     else if (!argcmp(argv[i],"-expand",2))     /* expand factor */
  352.       { if (++i<argc) expand=atof(argv[i]); }
  353.  
  354.     else if (!argcmp(argv[i],"-fg",3))          /* foreground color */
  355.       { if (++i<argc) fgstr = argv[i]; }
  356.     
  357.     else if (!argcmp(argv[i],"-fixed",3))       /* fixed aspect ratio */
  358.       fixedaspect++;
  359.     
  360.     else if (!argcmp(argv[i],"-geometry",2))    /* geometry */
  361.       { if (++i<argc) maingeom = argv[i]; }
  362.     
  363.     else if (!argcmp(argv[i],"-hi",3))            /* highlight */
  364.       { if (++i<argc) histr = argv[i]; }
  365.     
  366.     else if (!argcmp(argv[i],"-hsv",3))         /* hsvmode */
  367.       hsvmode = 1;
  368.     
  369.     else if (!argcmp(argv[i],"-igeometry",3))    /* infogeom */
  370.       { if (++i<argc) infogeom = argv[i]; }
  371.     
  372.     else if (!argcmp(argv[i],"-imap",3))    /* imap */
  373.       imap++;
  374.     
  375.     else if (!argcmp(argv[i],"-keeparound",2))  /* keeparound */
  376.       keeparound = !keeparound;
  377.     
  378.     else if (!argcmp(argv[i],"-lo",3))            /* lowlight */
  379.       { if (++i<argc) lostr = argv[i]; }
  380.     
  381.     else if (!argcmp(argv[i],"-max",4))            /* auto maximize */
  382.       automax++;
  383.     
  384.     else if (!argcmp(argv[i],"-maxpect",5))     /* auto maximize */
  385.       { automax++; fixedaspect++; }
  386.     
  387.     else if (!argcmp(argv[i],"-mono",3))    /* mono */
  388.       mono++;
  389.     
  390.     else if (!argcmp(argv[i],"-ncols",3))       /* ncols */
  391.       { if (++i<argc) { ncols=abs(atoi(argv[i])); noglob++; } }
  392.     
  393.     else if (!argcmp(argv[i],"-nglobal",3))     /* no global colors */
  394.       noglob++;
  395.     
  396.     else if (!argcmp(argv[i],"-ninstall",3))    /* don't install colormaps */
  397.       ninstall=1;
  398.  
  399.     else if (!argcmp(argv[i],"-nopos",4))       /* nopos */
  400.       nopos++;
  401.  
  402.     else if (!argcmp(argv[i],"-noqcheck",4))    /* noqcheck */
  403.       noqcheck++;
  404.  
  405.     else if (!argcmp(argv[i],"-owncmap",2))     /* own colormap */
  406.       owncmap++;
  407.  
  408.     else if (!argcmp(argv[i],"-perfect",2))     /* perfect colors */
  409.       perfect++;  
  410.     
  411.     else if (!argcmp(argv[i],"-quit",2))        /* auto-quit if -root */
  412.       autoquit++;
  413.     
  414.     else if (!argcmp(argv[i],"-rbg",3))         /* root background color */
  415.       { if (++i<argc) rootbgstr = argv[i]; }
  416.     
  417.     else if (!argcmp(argv[i],"-rfg",3))         /* root foreground color */
  418.       { if (++i<argc) rootfgstr = argv[i]; }
  419.     
  420.     else if (!argcmp(argv[i],"-rgb",4))         /* rgb mode */
  421.       hsvmode = 0;
  422.     
  423.     else if (!argcmp(argv[i],"-rmode",3))    /* root pattern */
  424.       { if (++i<argc) rootMode = abs(atoi(argv[i])); useroot++; }
  425.     
  426.     else if (!argcmp(argv[i],"-root",3))        /* use root window */
  427.       useroot++;
  428.     
  429.     else if (!argcmp(argv[i],"-rw",3))          /* use r/w color */
  430.       rwcolor++;
  431.     
  432.     else if (!argcmp(argv[i],"-slow24",3))      /* slow 24-to-8 conversion */
  433.       slow24++;
  434.     
  435.     else if (!argcmp(argv[i],"-smooth",3))      /* autosmooth */
  436.       autosmooth = !autosmooth;
  437.  
  438.     else if (!argcmp(argv[i],"-visual",2))    /* visual */
  439.       { if (++i<argc) visualstr = argv[i]; }
  440.     
  441.     else if (!argcmp(argv[i],"-wait",3))    /* secs to wait between pics */
  442.       { if (++i<argc) waitsec = abs(atoi(argv[i])); }
  443.     
  444.     else if (!argcmp(argv[i],"-white",3))    /* white color */
  445.       { if (++i<argc) whitestr = argv[i]; }
  446.     
  447.     else if (!argcmp(argv[i],"-wloop",3))    /* waitloop */
  448.       waitloop++;
  449.     
  450.     else Syntax();
  451.   }
  452.  
  453.   RANGE(curstype,0,254);
  454.   curstype = curstype & 0xfe;   /* clear low bit to make curstype even */
  455.  
  456.   if (expand == 0.0) Syntax();
  457.   if (rootMode < 0 || rootMode > RM_MAX) RmodeSyntax();
  458.  
  459.   if (DEBUG) XSynchronize(theDisp, True);
  460.  
  461.   /* if using root, generally gotta map ctrl window, 'cause there won't be
  462.      any way to ask for it.  (no kbd or mouse events from rootW) */
  463.   if (useroot && !autoquit) ctrlmap = -1;    
  464.  
  465.   /* must not install colormaps on rootW */
  466.   if (useroot) { owncmap = perfect=0;  noglob = 1; } 
  467.  
  468.   if (owncmap) perfect = 1;
  469.  
  470.   if (nopos) { maingeom = infogeom = ctrlgeom = gamgeom = NULL; }
  471.  
  472.   /* if -root and -maxp, make sure we're using a 'centered' mode */
  473.   if (useroot && fixedaspect && automax && rootMode < RM_CENTER)
  474.     rootMode = RM_CSOLID;
  475.  
  476.  
  477.   /*****************************************************/
  478.   /*** X Setup                                       ***/
  479.   /*****************************************************/
  480.   
  481.   theScreen = DefaultScreen(theDisp);
  482.   theCmap   = DefaultColormap(theDisp, theScreen);
  483.   rootW     = RootWindow(theDisp,theScreen);
  484.   theGC     = DefaultGC(theDisp,theScreen);
  485.   theVisual = DefaultVisual(theDisp,theScreen);
  486.   ncells    = DisplayCells(theDisp, theScreen);
  487.   dispDEEP  = DisplayPlanes(theDisp,theScreen);
  488.   vrWIDE = dispWIDE  = DisplayWidth(theDisp,theScreen);
  489.   vrHIGH = dispHIGH  = DisplayHeight(theDisp,theScreen);
  490.   maxWIDE = dispWIDE;  maxHIGH = dispHIGH;
  491.  
  492.   if (visualstr) {     /* handle non-default visual */
  493.     int vclass = -1;
  494.     lower_str(visualstr);
  495.     if      (!strcmp(visualstr,"staticgray"))  vclass = StaticGray;
  496.     else if (!strcmp(visualstr,"staticcolor")) vclass = StaticColor;
  497.     else if (!strcmp(visualstr,"truecolor"))   vclass = TrueColor;
  498.     else if (!strcmp(visualstr,"grayscale"))   vclass = GrayScale;
  499.     else if (!strcmp(visualstr,"pseudocolor")) vclass = PseudoColor;
  500.     else if (!strcmp(visualstr,"directcolor")) vclass = DirectColor;
  501.     else {
  502.       fprintf(stderr,"%s: Unrecognized visual type '%s'.  %s\n",
  503.           cmd, visualstr, "Using server default.");
  504.     }
  505.  
  506.     if (vclass >= 0) {   /* try to find asked-for visual type */
  507.       XVisualInfo *vinfo, rvinfo;
  508.       int numvis, best;
  509.  
  510.       rvinfo.class = vclass;
  511.       vinfo = XGetVisualInfo(theDisp, VisualClassMask, &rvinfo, &numvis);
  512.       if (vinfo) {       /* choose the 'best' one, if multiple */
  513.     for (i=0, best=0; i<numvis; i++) {
  514.       if (vinfo[i].depth > vinfo[best].depth) best = i;
  515.     }
  516.     theVisual = vinfo[best].visual;
  517.     if (DEBUG) {
  518.       fprintf(stderr,"%s: using %s visual, depth = %d, screen = %d\n",
  519.           cmd, visualstr, vinfo[best].depth, vinfo[best].screen);
  520.       fprintf(stderr,"\tmasks: (0x%x,0x%x,0x%x), bits_per_rgb=%d\n",
  521.           vinfo[best].red_mask, vinfo[best].green_mask,
  522.           vinfo[best].blue_mask, vinfo[best].bits_per_rgb);
  523.     }
  524.     XFree((char *) vinfo);
  525.       }
  526.       else fprintf(stderr,"%s: Visual type '%s' not available.  %s\n",
  527.            cmd, visualstr, "Using server default.");
  528.     }
  529.   }
  530.     
  531.  
  532.   if (!useroot && limit2x) { maxWIDE *= 2;  maxHIGH *= 2; }
  533.  
  534.   XSetErrorHandler(xvErrorHandler);
  535.  
  536.   /* always search for virtual root window */
  537.   vrootW = rootW;
  538.   __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False);
  539.   XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children,
  540.          &numChildren);
  541.   for (i = 0; i < numChildren; i++) {
  542.     Atom actual_type;
  543.     int actual_format;
  544.     unsigned long nitems, bytesafter;
  545.     Window *newRoot = NULL;
  546.     XWindowAttributes xwa;
  547.     if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0, 1,
  548.       False, XA_WINDOW, &actual_type, &actual_format, &nitems,
  549.       &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) {
  550.       vrootW = *newRoot;
  551.       XGetWindowAttributes(theDisp, vrootW, &xwa);
  552.       vrWIDE = xwa.width;  vrHIGH = xwa.height;
  553.       dispDEEP = xwa.depth;
  554.       break;
  555.     }
  556.   }
  557.  
  558.   if (clrroot || useroot) {
  559.     /* have enough info to do a '-clear' now */
  560.     KillOldRootInfo();   /* if any */
  561.  
  562.     ClearRoot();
  563.     if (clrroot) Quit(0);
  564.   }
  565.  
  566.  
  567.   arrow     = XCreateFontCursor(theDisp,XC_top_left_arrow);
  568.   cross     = XCreateFontCursor(theDisp,curstype);
  569.  
  570.  
  571.   /* set up white,black colors */
  572.   white = WhitePixel(theDisp,theScreen);  whtRGB = 0xffffff;
  573.   black = BlackPixel(theDisp,theScreen);  blkRGB = 0x000000;
  574.  
  575.   if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
  576.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  577.     white = ecdef.pixel;
  578.     whtRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  579.   }
  580.  
  581.   if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
  582.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  583.     black = ecdef.pixel;
  584.     blkRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  585.   }
  586.  
  587.  
  588.   /* set up fg,bg colors */
  589.   fg = black;   bg = white;  fgRGB = blkRGB;  bgRGB = whtRGB;
  590.   if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
  591.       xvAllocColor(theDisp, theCmap, &ecdef)) {
  592.     fg = ecdef.pixel;
  593.     fgRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  594.   }
  595.  
  596.   if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
  597.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  598.     bg = ecdef.pixel;
  599.     bgRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  600.   }
  601.  
  602.  
  603.   /* set up root fg,bg colors */
  604.   rootfg = white;   rootbg = black;
  605.   if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
  606.       xvAllocColor(theDisp, theCmap, &ecdef))  rootfg = ecdef.pixel;
  607.   if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
  608.       xvAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
  609.  
  610.  
  611.   /* set up hi/lo colors */
  612.   i=0;
  613.   if (dispDEEP > 1) {   /* only if we're on a reasonable display */
  614.     if (histr && XParseColor(theDisp, theCmap, histr, &ecdef) &&
  615.     xvAllocColor(theDisp, theCmap, &ecdef))  { hicol = ecdef.pixel; i|=1; }
  616.     if (lostr && XParseColor(theDisp, theCmap, lostr, &ecdef) &&
  617.     xvAllocColor(theDisp, theCmap, &ecdef))  { locol = ecdef.pixel; i|=2; }
  618.   }
  619.  
  620.   if      (i==0) ctrlColor = 0;
  621.   else if (i==3) ctrlColor = 1;
  622.   else {  /* only got some of them */
  623.     if (i&1) xvFreeColors(theDisp, theCmap, &hicol, 1, 0L);
  624.     if (i&2) xvFreeColors(theDisp, theCmap, &locol, 1, 0L);
  625.     ctrlColor = 0;
  626.   }
  627.  
  628.   XSetForeground(theDisp,theGC,fg);
  629.   XSetBackground(theDisp,theGC,bg);
  630.  
  631.   infofg = fg;  infobg = bg;
  632.  
  633.   /* if '-mono' not forced, determine if we're on a grey or color monitor */
  634.   if (!mono) {
  635.     if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
  636.     if (theVisual->class == StaticGray || theVisual->class == GrayScale)
  637.       mono = 1;
  638.   }
  639.   
  640.  
  641.  
  642.   iconPix = XCreatePixmapFromBitmapData(theDisp, rootW, icon_bits,
  643.          icon_width, icon_height, 1, 0, 1);
  644.  
  645.   iconmask = XCreatePixmapFromBitmapData(theDisp, rootW, iconmask_bits,
  646.          icon_width, icon_height, 1, 0, 1);
  647.  
  648.  
  649.  
  650.   /* try to load fonts */
  651.   if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL && 
  652.        (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL && 
  653.        (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL && 
  654.        (mfinfo = XLoadQueryFont(theDisp,FONT4))==NULL && 
  655.        (mfinfo = XLoadQueryFont(theDisp,FONT5))==NULL) {
  656.     sprintf(str,
  657.         "couldn't open the following fonts:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s",
  658.         FONT1, FONT2, FONT3, FONT4, FONT5);
  659.     FatalError(str);
  660.   }
  661.   mfont=mfinfo->fid;
  662.   XSetFont(theDisp,theGC,mfont);
  663.   
  664.   if ( (monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL && 
  665.        (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL && 
  666.        (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL && 
  667.        (monofinfo = XLoadQueryFont(theDisp,MFONT4))==NULL) {
  668.     sprintf(str,"couldn't open the following fonts:\n\t%s\n\t%s\n\t%s\n\t%s",
  669.         MFONT1, MFONT2, MFONT3, MFONT4);
  670.     FatalError(str);
  671.   }
  672.   monofont=monofinfo->fid;
  673.   
  674.  
  675.  
  676.  
  677.   /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
  678.      case ncols = 0;  (ncols = max number of colors allocated.  on 1-bit
  679.      displays, no colors are allocated */
  680.  
  681.   if (ncols == -1) {
  682.     if (dispDEEP>1) ncols = 1 << ((dispDEEP>8) ? 8 : dispDEEP);
  683.     else ncols = 0;
  684.   }
  685.   else if (ncols>256) ncols = 256;       /* so program doesn't blow up */
  686.  
  687.  
  688.  
  689.   /* no filenames.  build one-name (stdio) list (if stdinflag) */
  690.   if (numnames==0) {
  691.     if (stdinflag) {  namelist[0] = STDINSTR; numnames = 1; }
  692.     else           {  namelist[0] = NULL;     numnames = 0; }
  693.   }
  694.  
  695.   if (numnames) MakeDispNames();
  696.  
  697.  
  698.  
  699.   /* create the info box window */
  700.   CreateInfo(infogeom);
  701.   XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask );
  702.   InfoBox(imap);     /* map it (or not) */
  703.   if (imap) {
  704.     RedrawInfo(0,0,INFOWIDE,INFOHIGH);  /* explicit draw if mapped */
  705.     XFlush(theDisp);
  706.   }
  707.  
  708.  
  709.   /* create the control box window */
  710.   CreateCtrl(ctrlgeom);
  711.   epicmode = EM_RAW;   SetEpicMode();
  712.   XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask);
  713.   if (ctrlmap < 0) {    /* map iconified */
  714.     XWMHints xwmh;
  715.     xwmh.initial_state = IconicState;
  716.     xwmh.flags = StateHint;
  717.     XSetWMHints(theDisp, ctrlW, &xwmh);
  718.     ctrlmap = 1;
  719.   }
  720.   CtrlBox(ctrlmap);     /* map it (or not) */
  721.   if (ctrlmap) {
  722.     RedrawCtrl(0,0,CTRLWIDE,CTRLHIGH);   /* explicit draw if mapped */
  723.     XFlush(theDisp);
  724.   }
  725.  
  726.  
  727.   /* create the directory window */
  728.   CreateDirW(NULL);
  729.   XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask);
  730.  
  731.  
  732.   /* create the gamma window */
  733.   CreateGam(gamgeom);
  734.   XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask);
  735.   GamBox(gmap);     /* map it (or not) */
  736.  
  737.  
  738.   /* create the ps window */
  739.   CreatePSD(NULL);
  740.  
  741. #ifdef HAVE_JPEG
  742.   CreateJPEGW();
  743. #endif
  744.  
  745.   GenerateFSGamma();
  746.  
  747.   LoadFishCursors();
  748.   SetCursors(-1);
  749.  
  750.   /* if we're not on a colormapped display, turn off rwcolor */
  751.   if ( (theVisual->class & 1 == 0 || theVisual->class == DirectColor) 
  752.       && rwcolor) {
  753.     fprintf(stderr,"xv: not a colormapped display.  'rwcolor' turned off.\n");
  754.     rwcolor = 0;
  755.   }
  756.  
  757.  
  758.   /* Do The Thing... */
  759.   MainLoop();
  760.   Quit(0);
  761.   return(0);
  762. }
  763.  
  764.  
  765.  
  766.  
  767. /***********************************/
  768. static int cpos = 0;
  769. void printoption(st)
  770. char *st;
  771. {
  772.   if (strlen(st) + cpos > 78) {
  773.     fprintf(stderr,"\n   ");
  774.     cpos = 3;
  775.   }
  776.  
  777.   fprintf(stderr,"%s ",st);
  778.   cpos = cpos + strlen(st) + 1;
  779. }
  780.  
  781. static void Syntax()
  782. {
  783.   fprintf(stderr, "Usage:\n");
  784.   printoption(cmd);
  785.   printoption("[-]");
  786.   printoption("[-2xlimit]");
  787.   printoption("[-aspect w:h]");
  788.   printoption("[-bg color]");
  789.   printoption("[-black color]");
  790.   printoption("[-bw width]");
  791.   printoption("[-cegeometry geom]");
  792.   printoption("[-cemap]");
  793.   printoption("[-cgeometry geom]");
  794.   printoption("[-clear]");
  795.   printoption("[-cmap]");
  796.   printoption("[-cursor char#]");
  797.   printoption("[-DEBUG level]");
  798.   printoption("[-display disp]");
  799.   printoption("[-dither]");
  800.   printoption("[-expand exp]");
  801.   printoption("[-fg color]");
  802.   printoption("[-fixed]");
  803.   printoption("[-geometry geom]");
  804.   printoption("[-help]");
  805.   printoption("[-hi color]");
  806.   printoption("[-hsv]");
  807.   printoption("[-igeometry geom]");
  808.   printoption("[-imap]");
  809.   printoption("[-keeparound]");
  810.   printoption("[-lo color]");
  811.   printoption("[-max]");
  812.   printoption("[-maxpect]");
  813.   printoption("[-mono]");
  814.   printoption("[-ncols #]");
  815.   printoption("[-nglobal]");
  816.   printoption("[-ninstall]");
  817.   printoption("[-nopos]");
  818.   printoption("[-noqcheck]");
  819.   printoption("[-owncmap]");
  820.   printoption("[-perfect]");
  821.   printoption("[-quit]");
  822.   printoption("[-rbg color]");
  823.   printoption("[-rfg color]");
  824.   printoption("[-rgb]");
  825.   printoption("[-rmode #]");
  826.   printoption("[-root]");
  827.   printoption("[-rw]");
  828.   printoption("[-slow24]");
  829.   printoption("[-smooth]");
  830.   printoption("[-visual type]");
  831.   printoption("[-wait seconds]");
  832.   printoption("[-white color]");
  833.   printoption("[-wloop]");
  834.   printoption("[filename ...]");
  835.   fprintf(stderr,"\n\n");
  836.   Quit(1);
  837. }
  838.  
  839.  
  840. /***********************************/
  841. static void RmodeSyntax()
  842. {
  843.   fprintf(stderr,"%s: unknown root mode '%d'.  Valid modes are:\n", 
  844.       cmd, rootMode);
  845.   fprintf(stderr,"\t0: tiling\n");
  846.   fprintf(stderr,"\t1: integer tiling\n");
  847.   fprintf(stderr,"\t2: mirrored tiling\n");
  848.   fprintf(stderr,"\t3: integer mirrored tiling\n");
  849.   fprintf(stderr,"\t4: centered tiling\n");
  850.   fprintf(stderr,"\t5: centered on a solid background\n");
  851.   fprintf(stderr,"\t6: centered on a 'warp' background\n");
  852.   fprintf(stderr,"\t7: centered on a 'brick' background\n");
  853.   fprintf(stderr,"\n");
  854.   Quit(1);
  855. }
  856.  
  857.  
  858. /***********************************/
  859. static int argcmp(a1, a2, minlen)
  860. char *a1, *a2;
  861. int minlen;
  862. {
  863.   /* does a string compare between a1 and a2.  To return '0', a1 and a2 
  864.      must match to the length of a2, and that length has to
  865.      be at least 'minlen'.  Otherwise, return non-zero */
  866.  
  867.   if (strlen(a1) < minlen || strlen(a2) < minlen) return 1;
  868.   if (strlen(a1) > strlen(a2)) return 1;
  869.  
  870.   return (strncmp(a1, a2, strlen(a1)));
  871. }
  872.  
  873.  
  874. /***********************************/
  875. static int openPic(filenum)
  876. int filenum;
  877. {
  878.   /* tries to load file #filenum (from 'namelist' list)
  879.    * returns 0 on failure (cleans up after itself)
  880.    * if successful, returns 1, creates mainW
  881.    *
  882.    * By the way, I'd just like to point out that this procedure has gotten
  883.    * *way* out of hand...
  884.    */
  885.  
  886.   int   i,filetype,freename, nw, nh;
  887.   char *tmp;
  888.   FILE *fp;
  889.   char *fullname,      /* full name of the original file */
  890.         filename[256], /* full name of the file to be loaded (could be /tmp) */
  891.         globnm[512];   /* globbed version of fullname of orig file */
  892.   byte  magicno[8];    /* first 8 bytes of file */
  893.  
  894.   normaspect = defaspect;
  895.  
  896.   WaitCursor();
  897.  
  898.   if (filenum == DFLTPIC) {
  899.     filename[0] = '\0';  basename[0] = '\0';  fullname = "";
  900.     LoadDfltPic();
  901.     goto GOTIMAGE;
  902.   }
  903.  
  904.  
  905.   if (filenum != LOADPIC) {
  906.     curname = filenum;
  907.     nList.selected = curname;
  908.     ScrollToCurrent(&nList);  /* have scrl/list show current */
  909.     XFlush(theDisp);    /* update NOW */
  910.   }
  911.  
  912.   /* clear any old error messages */
  913.  
  914.   formatStr[0] = '\0';
  915.   SetISTR(ISTR_INFO,"");
  916.   SetISTR(ISTR_WARNING,"");
  917.   infoMode = INF_STR;
  918.  
  919.   /* set up fullname and basename */
  920.  
  921.   if (filenum == LOADPIC) {
  922.     fullname = GetDirFName();
  923.     if (fullname[0] == '~') {
  924.       strcpy(globnm, fullname);
  925.       Globify(globnm);
  926.       fullname = globnm;
  927.     }
  928.   }
  929.   else fullname = namelist[filenum];
  930.  
  931.   tmp = rindex(fullname,'/');
  932.   if (!tmp) tmp = fullname; else tmp++;
  933.   strcpy(basename,tmp);
  934.   if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0) 
  935.     basename[strlen(basename)-2]='\0';     /* chop off .Z, if any */
  936.  
  937.   /* if fullname doesn't start with a '/' (ie, it's a relative path), 
  938.      (and it's not LOADPIC and it's not the special case '<stdin>') 
  939.      prepend 'initpath' to it */
  940.  
  941.   freename = 0;
  942.   if (filenum != LOADPIC && fullname[0] != '/' && 
  943.       strcmp(fullname,STDINSTR)!=0) {
  944.     char *tmp;
  945.     tmp = (char *) malloc(strlen(fullname) + strlen(initpath) + 2);
  946.     if (!tmp) FatalError("malloc 'filename' failed");
  947.     sprintf(tmp,"%s/%s", initpath, fullname);
  948.     fullname = tmp;
  949.     freename = 1;
  950.   }
  951.     
  952.  
  953.   /* uncompress if it's a .Z file */
  954.  
  955.   i = strlen(fullname);
  956.   if (i>2 && strcmp(fullname+i-2,".Z")==0) {
  957.     strcpy(filename,"/tmp/xvXXXXXX");
  958.     mktemp(filename);
  959.     sprintf(str,"%s -c %s >%s",UNCOMPRESS,fullname,filename);
  960.     SetISTR(ISTR_INFO,"Uncompressing '%s'...",basename);
  961.     if (system(str)) {
  962.       SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basename);
  963.       Warning();
  964.       goto FAILED;
  965.     }
  966.   WaitCursor();
  967.   }
  968.   else strcpy(filename,fullname);
  969.     
  970.  
  971.   /* if the file is stdio, write it out to a temp file */
  972.   if (strcmp(filename,STDINSTR)==0) {
  973.     FILE *fp;
  974.  
  975.     strcpy(filename,"/tmp/xvXXXXXX");
  976.     mktemp(filename);
  977.  
  978.     fp = fopen(filename,"w");
  979.     if (!fp) FatalError("can't write /tmp/xv****** file");
  980.     
  981.     while ( (i=getchar()) != EOF) putc(i,fp);
  982.     fclose(fp);
  983.   }
  984.  
  985.  
  986.   /* now, try to determine what type of file we've got by reading the
  987.      first couple bytes and looking for a Magic Number */
  988.  
  989.   fp=fopen(filename,"r");
  990.   if (!fp) {
  991.     static char *foo[] = { "\nBummer!" };
  992.     char  str[512];
  993.     sprintf(str,"Can't open file '%s'\n\n  %s.",filename,sys_errlist[errno]);
  994.     PopUp(str, foo, 1);
  995.     goto FAILED;
  996.   }
  997.  
  998.   fread(magicno,8,1,fp);  
  999.   fclose(fp);
  1000.  
  1001.   filetype = UNKNOWN;
  1002.   if (strncmp(magicno,"GIF87a",6)==0 ||
  1003.       strncmp(magicno,"GIF89a",6)==0) filetype = GIF;
  1004.  
  1005.   else if (strncmp(magicno,"VIEW",4)==0 ||
  1006.        strncmp(magicno,"WEIV",4)==0) filetype = PM;
  1007.  
  1008.   else if (magicno[0] == 'P' && magicno[1]>='1' && 
  1009.        magicno[1]<='6') filetype = PBM;
  1010.  
  1011.   else if (strncmp(magicno,"#define",7)==0) filetype = XBM;
  1012.  
  1013.   else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
  1014.        magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) filetype = SUNRAS;
  1015.  
  1016. #ifdef HAVE_JPEG
  1017.   else if (magicno[0]==0xff && magicno[1]==0xd8 && 
  1018.        magicno[2]==0xff) filetype = JFIF;
  1019. #endif
  1020.  
  1021.   if (filetype == UNKNOWN) {
  1022.     SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basename);
  1023.     Warning();
  1024.     goto FAILED;
  1025.   }
  1026.  
  1027.  
  1028.   SetISTR(ISTR_INFO,"Loading...");
  1029.  
  1030.   switch (filetype) {
  1031.   case GIF:    i = LoadGIF(filename,ncols);     break;
  1032.   case PM:     i = LoadPM (filename,ncols);     break;
  1033.   case PBM:    i = LoadPBM(filename,ncols);     break;
  1034.   case XBM:    i = LoadXBM(filename,ncols);     break;
  1035.   case SUNRAS: i = LoadSunRas(filename, ncols); break;
  1036. #ifdef HAVE_JPEG
  1037.   case JFIF:   i = LoadJFIF(filename, ncols);   break;
  1038. #endif
  1039.   }
  1040.  
  1041.   WaitCursor();
  1042.  
  1043.   if (i) {
  1044.     SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename);
  1045.     Warning();
  1046.     goto FAILED;
  1047.   }
  1048.  
  1049.  GOTIMAGE:
  1050.   /* successfully read this picture.  No failures from here on out */
  1051.  
  1052.   /* stick this file in the 'ctrlW' name list */
  1053.   if (filenum == LOADPIC) stickInList();
  1054.  
  1055.   /* clear old image before we start dicking with colors... */
  1056.   if (mainW && !useroot) {
  1057.     XClearArea(theDisp, mainW, 0,0, eWIDE, eHIGH, False);
  1058.     XFlush(theDisp);
  1059.   }
  1060.  
  1061.   if (filenum == LOADPIC) DirBox(0);   /* close the DirBox */
  1062.  
  1063.  
  1064.   /* if we read a /tmp file, delete it.  won't be needing it any more */
  1065.   if (strcmp(fullname,filename)!=0) unlink(filename);
  1066.  
  1067.  
  1068.   SetISTR(ISTR_INFO,formatStr);
  1069.     
  1070.   SetInfoMode(INF_PART);
  1071.   SetISTR(ISTR_FILENAME, (filenum==DFLTPIC) ? "<none>" : basename);
  1072.   SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
  1073.   SetISTR(ISTR_COLOR,"");
  1074.  
  1075.   /* adjust button in/activity */
  1076.   BTSetActive(&but[BCROP],0);  /* new picture, draw no cropping rectangle */
  1077.   BTSetActive(&but[BUNCROP], 0);
  1078.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  1079.   BTSetActive(&but[BPREV], (curname>0));
  1080.  
  1081.  
  1082.   normFact = 1;  nw = pWIDE;  nh = pHIGH;
  1083.   /* if pic is larger than screen, half picture until it fits on screen */
  1084.   while (nw > maxWIDE || nh > maxHIGH) {
  1085.     nw = nw / 2;  
  1086.     nh = nh / 2;
  1087.     normFact = normFact * 2;
  1088.   }
  1089.  
  1090.   if (normFact != 1) {
  1091.     char tstr[128];
  1092.     tmp = GetISTR(ISTR_WARNING);
  1093.     if (strlen(tmp)>0) sprintf(tstr, "%s  Shrunk %dX.", tmp, normFact);
  1094.                   else sprintf(tstr, "Shrunk %dX.", normFact);
  1095.     SetISTR(ISTR_WARNING,tstr);
  1096.   }
  1097.  
  1098.  
  1099.   /* expand:  if expansion is negative, treat it as a reciprocal */
  1100.   if (expand < 0.0) { eWIDE=(int)(pWIDE/expand);  eHIGH=(int)(pHIGH/expand); }
  1101.                else { eWIDE=(int)(pWIDE*expand);  eHIGH=(int)(pHIGH*expand); }
  1102.  
  1103.  
  1104.   if (eWIDE>maxWIDE || eHIGH>maxHIGH) {
  1105.     eWIDE = eWIDE / normFact;  eHIGH = eHIGH / normFact;
  1106.   }
  1107.  
  1108.  
  1109.   if (useroot) {
  1110.     int i,x,y;  unsigned int w,h;
  1111.     i = XParseGeometry(maingeom,&x,&y,&w,&h);
  1112.     if (i&WidthValue)  eWIDE = w;
  1113.     if (i&HeightValue) eHIGH = h;
  1114.     RANGE(eWIDE,1,maxWIDE);  RANGE(eHIGH,1,maxHIGH);
  1115.  
  1116.     if (rootMode == RM_TILE || rootMode == RM_IMIRROR) {
  1117.       /* make picture size a divisor of the rootW size.  round down */
  1118.       i = (dispWIDE + eWIDE-1) / eWIDE;   eWIDE = (dispWIDE + i-1) / i;
  1119.       i = (dispHIGH + eHIGH-1) / eHIGH;   eHIGH = (dispHIGH + i-1) / i;
  1120.     }
  1121.   }
  1122.  
  1123.   cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;  cXOFF = cYOFF = 0;
  1124.   SetCropString(but[BCROP].active);
  1125.  
  1126.   if (automax) { 
  1127.     eWIDE = dispWIDE;  eHIGH = dispHIGH;
  1128.     if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  1129.   }
  1130.  
  1131.   if (useroot) {
  1132.     mainW = vrootW;
  1133.  
  1134.     if (theVisual->class & 1) {
  1135.       /* clear old root pixmap before doing the 'alloc colors scene' 
  1136.      to avoid annoying 'rainbow' effect as colors are realloced */
  1137.       ClearRoot();
  1138.     }
  1139.   }
  1140.  
  1141.   SortColormap();
  1142.  
  1143.   /* save the desired RGB colormap (before dicking with it) */
  1144.   for (i=0; i<numcols; i++) { 
  1145.     rorg[i] = rcmap[i] = r[i];  
  1146.     gorg[i] = gcmap[i] = g[i];  
  1147.     borg[i] = bcmap[i] = b[i];  
  1148.   }
  1149.  
  1150.   NewCMap();
  1151.   GammifyColors();
  1152.  
  1153.   WaitCursor();
  1154.   if (rwcolor) AllocRWColors();  else AllocColors();
  1155.   ChangeEC(0);
  1156.  
  1157.   WaitCursor();
  1158.   if (autosmooth || normFact != 1) Smooth();
  1159.              else Resize(eWIDE,eHIGH);
  1160.  
  1161.   if ((autodither || filenum == DFLTPIC) && !autosmooth && ncols>0)
  1162.     ColorDither(NULL, eWIDE, eHIGH);
  1163.  
  1164.  
  1165.   WaitCursor();
  1166.   HandleDispMode();   /* create root pic, or mainW, depending... */
  1167.     
  1168.   if (LocalCmap) {
  1169.     XSetWindowAttributes xswa;
  1170.     if (!ninstall) XInstallColormap(theDisp,LocalCmap);
  1171.     xswa.colormap = LocalCmap;
  1172.     XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
  1173.     XChangeWindowAttributes(theDisp,gamW,CWColormap,&xswa);
  1174.   }
  1175.  
  1176.   tmp = GetISTR(ISTR_COLOR);
  1177.   SetISTR(ISTR_INFO,"%s  %s",formatStr, tmp);
  1178.     
  1179.   SetInfoMode(INF_FULL);
  1180.   if (freename) free(fullname);
  1181.  
  1182.   SetCursors(-1);
  1183.  
  1184.   if (dirUp!=BLOAD) {
  1185.     /* put current filename into the 'save-as' filename */
  1186.     if      (strcmp(filename,STDINSTR)==0) SetDirFName("stdin");
  1187.     else if (filenum == DFLTPIC)           SetDirFName("");
  1188.     else SetDirFName(basename);
  1189.   }
  1190.     
  1191.   return 1;
  1192.  
  1193.   
  1194.  FAILED:
  1195.   SetCursors(-1);
  1196.   SetInfoMode(INF_STR);
  1197.   if (strcmp(fullname,filename)!=0) unlink(filename);   /* kill /tmp file */
  1198.   if (freename) free(fullname);
  1199.   return 0;
  1200. }
  1201.  
  1202.  
  1203.  
  1204.  
  1205. /***********************************/
  1206. static void closePic()
  1207. {
  1208.   /* kill all resources used for this picture.
  1209.      this would include the window, any allocated colors, pic, epic, 
  1210.      theImage, etc. */
  1211.  
  1212.   if (!useroot) {
  1213.     /* turn off configure events */
  1214.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  1215.          | ButtonPressMask
  1216.          | EnterWindowMask | LeaveWindowMask);
  1217.   }
  1218.  
  1219.  
  1220.   FreeAllColors();
  1221.  
  1222.  
  1223.   if (epic != cpic && epic != NULL) free(epic);
  1224.   if (cpic !=  pic && cpic != NULL) free(cpic);
  1225.   if (pic != NULL) free(pic);
  1226.   if (theImage != NULL) XDestroyImage(theImage);
  1227.   theImage = NULL;
  1228.   pic = epic = cpic = NULL;
  1229.  
  1230.   SetInfoMode(INF_STR);
  1231. }
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239. /****************/
  1240. static void OpenFirstPic()
  1241. /****************/
  1242. {
  1243.   int i;
  1244.  
  1245.   if (!numnames) {  openPic(DFLTPIC);  return; }
  1246.  
  1247.   for (i=0; i<numnames; i++) {
  1248.     if (openPic(i)) return;    /* success */
  1249.   }
  1250.  
  1251.   if (numnames>1) FatalError("couldn't open any pictures");
  1252.   else Quit(-1);
  1253. }
  1254.  
  1255.  
  1256. /****************/
  1257. static void OpenNextPic()
  1258. /****************/
  1259. {
  1260.   int i;
  1261.  
  1262.   for (i=curname+1; i<numnames; i++) {
  1263.     if (openPic(i)) return;    /* success */
  1264.   }
  1265.  
  1266.   openPic(DFLTPIC);
  1267. }
  1268.  
  1269.  
  1270. /****************/
  1271. static void OpenNextQuit()
  1272. /****************/
  1273. {
  1274.   int i;
  1275.  
  1276.   for (i=curname+1; i<numnames; i++) {
  1277.     if (openPic(i)) return;    /* success */
  1278.   }
  1279.  
  1280.   Quit(0);
  1281. }
  1282.  
  1283.  
  1284. /****************/
  1285. static void OpenNextLoop()
  1286. /****************/
  1287. {
  1288.   int i,j;
  1289.  
  1290.   j = 0;
  1291.   while (1) {
  1292.     for (i=curname+1; i<numnames; i++) {  /* load next picture */
  1293.       if (openPic(i)) return;
  1294.     }
  1295.     curname = -1;                         /* back to first in list */
  1296.     if (j) break;                         /* we're in a 'failure loop' */
  1297.     j++;
  1298.   }
  1299.  
  1300.   openPic(DFLTPIC);
  1301. }
  1302.  
  1303.  
  1304. /****************/
  1305. static void OpenPrevPic()
  1306. /****************/
  1307. {
  1308.   int i;
  1309.  
  1310.   for (i=curname-1; i>=0; i--) {
  1311.     if (openPic(i)) return;    /* success */
  1312.   }
  1313.  
  1314.   openPic(DFLTPIC);
  1315. }
  1316.  
  1317.  
  1318. /****************/
  1319. static void OpenNamedPic()
  1320. /****************/
  1321. {
  1322.   if (!openPic(LOADPIC)) openPic(DFLTPIC);
  1323. }
  1324.  
  1325.  
  1326.  
  1327.  
  1328.  
  1329. /****************/
  1330. static void MainLoop()
  1331. /****************/
  1332. {
  1333.   /* search forward until we manage to display a picture, 
  1334.      then call EventLoop.  EventLoop will eventually return 
  1335.      NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */
  1336.  
  1337.   int i;
  1338.  
  1339.   OpenFirstPic();   /* find first displayable picture, exit if none */
  1340.  
  1341.   if (useroot && autoquit) Quit(0);
  1342.  
  1343.   while ((i=EventLoop()) != QUIT) {
  1344.     if      (i==NEXTPIC && curname<numnames-1)  { closePic(); OpenNextPic(); }
  1345.     else if (i==PREVPIC && curname>0)  { closePic(); OpenPrevPic(); }
  1346.     else if (i==NEXTQUIT) { closePic(); OpenNextQuit(); }
  1347.     else if (i==NEXTLOOP) { closePic(); OpenNextLoop(); }
  1348.     else if (i==LOADPIC)  { closePic(); OpenNamedPic(); }
  1349.  
  1350.     else if (i==DELETE)   {
  1351.       closePic();
  1352.       if (nList.nstr == 0 && !keeparound) Quit(0);
  1353.  
  1354.       if (curname >= 0 && curname < numnames) {   /* there's a selection */
  1355.     if (!openPic(curname)) openPic(DFLTPIC);
  1356.       }
  1357.       else openPic(DFLTPIC);
  1358.     }
  1359.  
  1360.     else if (i>=0) {
  1361.       closePic();
  1362.       if (!openPic(i)) openPic(DFLTPIC);
  1363.     }
  1364.  
  1365.   }
  1366. }
  1367.  
  1368.  
  1369.  
  1370. /***********************************/
  1371. static void CreateMainWindow(geom,name)
  1372.      char *geom, *name;
  1373. {
  1374.   XSetWindowAttributes xswa;
  1375.   unsigned int         xswamask;
  1376.   XWindowAttributes    xwa;
  1377.   XWMHints             xwmh;
  1378.   XSizeHints           hints;
  1379.   XClassHint           classh;
  1380.   int                  i,x,y,ew,eh;
  1381.   unsigned int         w,h;
  1382.   char                 winname[128], iconname[128];
  1383.  
  1384.   /*
  1385.    * this function mainly deals with parsing the geometry spec correctly.
  1386.    * More trouble than it should be, and probably more trouble than
  1387.    * it has to be, but who can tell these days, what with all those
  1388.    * Widget-usin' Weenies out there...
  1389.    */
  1390.  
  1391.   ew = eWIDE;  eh = eHIGH;
  1392.   x = y = w = h = 1;
  1393.   i = XParseGeometry(geom,&x,&y,&w,&h);
  1394.  
  1395.   if (i&WidthValue)  eWIDE = w;
  1396.   if (i&HeightValue) eHIGH = h;
  1397.  
  1398.   if (eWIDE > maxWIDE || eHIGH > maxHIGH) {
  1399.     eWIDE = eWIDE / normFact;
  1400.     eHIGH = eHIGH / normFact;
  1401.   }
  1402.   if (eWIDE < 1) eWIDE = 1;
  1403.   if (eHIGH < 1) eHIGH = 1;
  1404.  
  1405.   if (fixedaspect && i&WidthValue && i&HeightValue) 
  1406.     FixAspect(0,&eWIDE,&eHIGH);
  1407.   else if (i&WidthValue && i&HeightValue) 
  1408.     { RANGE(eWIDE,1,maxWIDE);  RANGE(eHIGH,1,maxHIGH); }
  1409.   else FixAspect(1,&eWIDE,&eHIGH);
  1410.  
  1411.  
  1412.   /* always use PPosition with tvtwm */
  1413.   if ((i&XValue || i&YValue) && vrootW == rootW) hints.flags = USPosition;  
  1414.                        else hints.flags = PPosition;
  1415.  
  1416.   hints.flags |= USSize;
  1417.  
  1418.   if (i&XValue && i&XNegative) x = vrWIDE - eWIDE - abs(x);
  1419.   if (i&YValue && i&YNegative) y = vrHIGH - eHIGH - abs(y);
  1420.  
  1421.   if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE;   /* keep on screen */
  1422.   if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH;
  1423.  
  1424.   if (eWIDE < 1) eWIDE = 1;
  1425.   if (eHIGH < 1) eHIGH = 1;
  1426.  
  1427.   hints.x = x;                  hints.y = y;
  1428.   hints.width = eWIDE;          hints.height = eHIGH;
  1429.   hints.max_width  = maxWIDE;  hints.max_height = maxHIGH;
  1430.   hints.flags |= PMaxSize;
  1431.  
  1432.   xswa.background_pixel = bg;
  1433.   xswa.border_pixel     = fg;
  1434.   xswamask = CWBackPixel | CWBorderPixel;
  1435.  
  1436.   if (mainW) {
  1437.     GetWindowPos(&xwa);
  1438.  
  1439.     /* generate an expose event if window hasn't changed size */
  1440.     if (xwa.width == eWIDE && xwa.height == eHIGH) 
  1441.       XClearArea(theDisp, mainW, 0,0, eWIDE, eHIGH, True);  
  1442.  
  1443.     xwa.width = eWIDE;  xwa.height = eHIGH;
  1444.     SetWindowPos(&xwa);
  1445.     hints.flags = PSize | PMaxSize;
  1446.   } 
  1447.  
  1448.   else {
  1449.     mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,bwidth,CopyFromParent,
  1450.               CopyFromParent, CopyFromParent, xswamask, &xswa);
  1451.     if (!mainW) FatalError("can't create window!");
  1452.  
  1453.     XSetTransientForHint(theDisp, psW, mainW);
  1454. #ifdef HAVE_JPEG
  1455.     XSetTransientForHint(theDisp, jpegW, mainW);
  1456. #endif
  1457.   }
  1458.  
  1459.  
  1460.   if (name[0] == '\0') {
  1461.     sprintf(winname, "xv");
  1462.     sprintf(iconname,"xv");
  1463.   }
  1464.   else {
  1465.     sprintf(winname,"xv %s",name);
  1466.     sprintf(iconname,"%s",name);
  1467.   }
  1468.  
  1469.   XSetStandardProperties(theDisp,mainW,winname,iconname,None,NULL,0,&hints);
  1470.  
  1471.   xwmh.input = True;
  1472.   xwmh.flags = InputHint;
  1473.  
  1474.   if (iconPix) { 
  1475.     xwmh.icon_pixmap = iconPix;  
  1476.     xwmh.icon_mask   = iconmask;  
  1477.     xwmh.flags |= ( IconPixmapHint | IconMaskHint) ;
  1478.   }
  1479.   XSetWMHints(theDisp, mainW, &xwmh);
  1480.  
  1481.   classh.res_name = "xv";
  1482.   classh.res_class = "XVroot";
  1483.   XSetClassHint(theDisp, mainW, &classh);
  1484.  
  1485. #ifdef FOO
  1486.   if (ew != eWIDE || eh != eHIGH) {
  1487.     /* kill old Ximage so that Resize will be forced to generate a new one */
  1488.     if (theImage != NULL) XDestroyImage(theImage);
  1489.     Resize(eWIDE, eHIGH);   /* just in case size has changed */
  1490.   }
  1491. #endif
  1492.  
  1493. }
  1494.  
  1495.  
  1496. /***********************************/
  1497. void FixAspect(grow,w,h)
  1498. int   grow;
  1499. int   *w, *h;
  1500. {
  1501.   /* computes new values of eWIDE and eHIGH which will have aspect ratio
  1502.      'normaspect'.  If 'grow' it will preserve aspect by enlarging, 
  1503.      otherwise, it will shrink to preserve aspect ratio.  
  1504.      Returns these values in 'w' and 'h' */
  1505.  
  1506.   float xr,yr,curaspect,a,exp;
  1507.  
  1508.   *w = eWIDE;  *h = eHIGH;
  1509.  
  1510.   /* xr,yr are expansion factors */
  1511.   xr = ((float) eWIDE) / cWIDE;
  1512.   yr = ((float) eHIGH) / cHIGH;
  1513.   curaspect  = xr / yr;
  1514.  
  1515.   /* if too narrow & shrink, shrink height.  too wide and grow, grow height */
  1516.   if ((curaspect < normaspect && !grow) || 
  1517.       (curaspect > normaspect &&  grow)) {    /* modify height */
  1518.     exp = curaspect / normaspect;
  1519.     *h = (int) (eHIGH * exp + .5);
  1520.   }
  1521.  
  1522.   /* if too narrow & grow, grow width.  too wide and shrink, shrink width */
  1523.   if ((curaspect < normaspect &&  grow) || 
  1524.       (curaspect > normaspect && !grow)) {    /* modify width */
  1525.     exp = normaspect / curaspect;
  1526.     *w = (int) (eWIDE * exp + .5);
  1527.   }
  1528.  
  1529.  
  1530.   /* shrink to fit screen without changing aspect ratio */
  1531.   if (*w>maxWIDE) {
  1532.     int i;
  1533.     a = (float) *w / maxWIDE;
  1534.     *w = maxWIDE;
  1535.     i = (int) (*h / a + .5);        /* avoid freaking some optimizers */
  1536.     *h = i;
  1537.   }
  1538.  
  1539.   if (*h>maxHIGH) {
  1540.     a = (float) *h / maxHIGH;
  1541.     *h = maxHIGH;
  1542.     *w = (int) (*w / a + .5);
  1543.   }
  1544.  
  1545.   if (*w < 1) *w = 1;
  1546.   if (*h < 1) *h = 1;
  1547. }
  1548.  
  1549.  
  1550. /***********************************/
  1551. static void MakeDispNames()
  1552. {
  1553.   int   prelen, n, i, done;
  1554.   char *suffix, *strchr();
  1555.  
  1556.   suffix = namelist[0];
  1557.   prelen = 0;   /* length of prefix to be removed */
  1558.   n = i = 0;    /* shut up pesky compiler warnings */
  1559.  
  1560.   done = 0;
  1561.   while (!done) {
  1562.     suffix = strchr(suffix,'/');    /* find next '/' in file name */
  1563.     if (!suffix) break;
  1564.  
  1565.     suffix++;                       /* go past it */
  1566.     n = suffix - namelist[0];
  1567.     for (i=1; i<numnames; i++) {
  1568.       if (strncmp(namelist[0], namelist[i], n)!=0) { done=1; break; }
  1569.     }
  1570.  
  1571.     if (!done) prelen = n;
  1572.   }
  1573.  
  1574.   for (i=0; i<numnames; i++)
  1575.     dispnames[i] = namelist[i] + prelen;
  1576. }
  1577.  
  1578.  
  1579. /***********************************/
  1580. static void stickInList()
  1581. {
  1582.   /* stick current name (from 'load' box) and current working directory
  1583.      into 'namelist' */
  1584.  
  1585.   char *name, *fullname;
  1586.   char cwd[MAXPATHLEN];
  1587.   char *strchr();
  1588.  
  1589.   if (numnames == MAXNAMES) return;  /* full up */
  1590.  
  1591.   name = GetDirFName();
  1592.   if (name[0] != '/') {  /* prepend current working path */
  1593.     GETWD(cwd);
  1594.  
  1595.     fullname = (char *) malloc(strlen(cwd) + strlen(name) + 2);
  1596.     if (!fullname) FatalError("couldn't alloc 'fullname' in stickInList()\n");
  1597.  
  1598.     sprintf(fullname, "%s/%s", cwd, name);
  1599.   }
  1600.  
  1601.   else {                 /* copy name to fullname */
  1602.     fullname = (char *) malloc(strlen(name) + 1);
  1603.     if (!fullname) FatalError("couldn't alloc 'fullname' in stickInList()\n");
  1604.     strcpy(fullname, name);
  1605.   }
  1606.  
  1607.   namelist[numnames] = fullname;
  1608.  
  1609.   /* figure out how much of name can be shown */
  1610.   if (StringWidth(fullname) > (CTRL_LISTW-10)) {   /* has to be truncated */
  1611.     char *tmp;
  1612.     int   prelen = 0;
  1613.  
  1614.     tmp = fullname;
  1615.     while (1) {
  1616.       tmp = strchr(tmp,'/');   /* find next (forward) '/' in filename */
  1617.       if (!tmp) break;
  1618.  
  1619.       tmp++;                   /* move to char following the '/' */
  1620.       prelen = tmp - fullname;
  1621.       if (StringWidth(tmp) <= (CTRL_LISTW-10)) break;   /* we're cool now */
  1622.     }
  1623.  
  1624.     dispnames[numnames] = fullname + prelen;
  1625.   }
  1626.   else dispnames[numnames] = fullname;
  1627.  
  1628.   numnames++;
  1629.   if (numnames>0) BTSetActive(&but[BDELETE],1);
  1630.  
  1631.  
  1632.   LSNewData(&nList, dispnames, numnames);
  1633.   nList.selected = numnames-1;
  1634.   curname = numnames - 1;
  1635.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  1636.   BTSetActive(&but[BPREV], (curname>0));
  1637.  
  1638.   ScrollToCurrent(&nList);
  1639.   XClearArea(theDisp, ctrlW, 0, 0, 200, 40, True);  /* redraw part of ctrlW */
  1640. }
  1641.  
  1642.  
  1643. /***********************************/
  1644. int DeleteCmd()
  1645. {
  1646.   /* 'delete' button was pressed.  Pop up a dialog box to determine
  1647.      what should be deleted, then do it.
  1648.      returns '1' if THE CURRENTLY VIEWED entry was deleted from the list, 
  1649.      in which case the 'selected' filename on the ctrl list is now 
  1650.      different, and should be auto-loaded, or something */
  1651.  
  1652.   static char *bnames[] = { "\nList Entry", "\004Disk File", "\033Cancel" };
  1653.   char str[512];
  1654.   int  del, i, delnum, rv;
  1655.  
  1656.   /* failsafe */
  1657.   delnum = nList.selected;
  1658.   if (delnum < 0 || delnum >= numnames) return 0;
  1659.  
  1660.   sprintf(str,"What do you wish to delete?\n\n%s%s",
  1661.       "'List Entry' deletes selection from list.\n",
  1662.       "'Disk File' deletes file associated with selection.");
  1663.  
  1664.   del = PopUp(str, bnames, 3);
  1665.   
  1666.   if (del == 2) return 0;   /* cancel */
  1667.   
  1668.   if (del == 1) {           /* 'Disk File' */
  1669.     char *name;
  1670.     if (namelist[delnum][0] != '/') {    /* prepend 'initpath' */
  1671.       name = (char *) malloc(strlen(namelist[delnum]) + strlen(initpath) + 2);
  1672.       if (!name) FatalError("malloc in DeleteCmd failed\n");
  1673.       sprintf(name,"%s/%s", initpath, namelist[delnum]);
  1674.     }
  1675.     else name = namelist[delnum];
  1676.     i = unlink(name);
  1677.     if (i) {
  1678.       static char *foo[] = { "\nPity!" };
  1679.       sprintf(str,"Can't delete file '%s'\n\n  %s.", name, sys_errlist[errno]);
  1680.       PopUp(str, foo, 1);
  1681.       return 0;
  1682.     }
  1683.   }
  1684.  
  1685.  
  1686.   /* remove from list on either 'List Entry' or (successful) 'Disk File' */
  1687.  
  1688.   /* determine if namelist[delnum] needs to be freed or not */
  1689.   for (i=0; i<mainargc && mainargv[i] != namelist[delnum]; i++) ;
  1690.   if (i == mainargc) {  /* not found.  free it */
  1691.     free(namelist[delnum]);
  1692.   }
  1693.  
  1694.   if (delnum != numnames-1) {
  1695.     /* snip out of namelist and dispnames lists */
  1696.     bcopy(&namelist[delnum+1], &namelist[delnum], 
  1697.       (numnames - delnum - 1) * sizeof(namelist[0]));
  1698.  
  1699.     bcopy(&dispnames[delnum+1], &dispnames[delnum], 
  1700.       (numnames - delnum - 1) * sizeof(dispnames[0]));
  1701.   }
  1702.   
  1703.   numnames--;
  1704.   if (numnames==0) BTSetActive(&but[BDELETE],0);
  1705.  
  1706.   nList.nstr = numnames;
  1707.   nList.selected = delnum;
  1708.  
  1709.   if (nList.selected >= numnames) nList.selected = numnames-1;
  1710.   SCSetRange(&nList.scrl, 0, numnames - nList.nlines, 
  1711.          nList.scrl.val, nList.nlines-1);
  1712.   ScrollToCurrent(&nList);
  1713.   XClearArea(theDisp, ctrlW, 0, 0, 200, 40, True);  /* redraw part of ctrlW */
  1714.  
  1715.   rv = 0;
  1716.   if (delnum == curname) {      /* deleted the viewed file */
  1717.     curname = nList.selected;
  1718.     rv = 1;                     /* auto-load currently 'selected' filename */
  1719.   }
  1720.   else if (delnum < curname) curname = (curname > 0) ? curname-1 : 0;
  1721.   else if (delnum > curname);
  1722.  
  1723.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  1724.   BTSetActive(&but[BPREV], (curname>0));
  1725.   return rv;
  1726. }
  1727.  
  1728.  
  1729.  
  1730. /***********************************/
  1731. void HandleDispMode()
  1732. {
  1733.   /* handles a change in the display mode (windowed/root).
  1734.      Also, called to do the 'right' thing when opening a picture
  1735.      displays epic, in current size, UNLESS we've selected an 'integer'
  1736.      root tiling thingy, in which case we resize epic appropriately */
  1737.  
  1738.   static int haveoldinfo = 0;
  1739.   static Window            oldMainW;
  1740.   static int               oldPerfect, oldNoglob, oldOwnCmap;
  1741.   static int               hadLocalCmap;
  1742.   static XSizeHints        oldHints;
  1743.   static XWindowAttributes oldXwa;
  1744.   int i;
  1745.  
  1746.  
  1747.   if (dispMB.selected == 0) {        /* windowed */
  1748.     if (useroot) ClearRoot();
  1749.  
  1750.     if (mainW == NULL || useroot) {  /* window not created */
  1751.       useroot = 0;  
  1752.  
  1753.       if (haveoldinfo) {             /* just remap mainW and resize it */
  1754.     char wnam[128], inam[128];
  1755.  
  1756.     mainW = oldMainW;
  1757.  
  1758.     perfect = oldPerfect;
  1759.     noglob  = oldNoglob;
  1760.     owncmap = oldOwnCmap;
  1761.     if (hadLocalCmap) {          /* use 'perfect' again */
  1762.       FreeAllColors();
  1763.       if (rwcolor) AllocRWColors();  else AllocColors();
  1764.       CreateXImage();
  1765.     }
  1766.  
  1767.     sprintf(wnam,"xv %s",basename);
  1768.     sprintf(inam,"%s",basename);
  1769.     XSetStandardProperties(theDisp,mainW,wnam,inam,None,NULL,0,&oldHints);
  1770.  
  1771.     oldXwa.width = eWIDE;  oldXwa.height = eHIGH;
  1772.     SetWindowPos(&oldXwa);
  1773.     XMapWindow(theDisp, mainW);
  1774.       }
  1775.  
  1776.       else {                         /* first time.  need to create mainW */
  1777.     CARD32 data[2];  Atom prop;
  1778.  
  1779.     mainW = NULL;
  1780.     CreateMainWindow(maingeom, basename);
  1781.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  1782.              | StructureNotifyMask | ButtonPressMask
  1783.              | EnterWindowMask | LeaveWindowMask );
  1784.  
  1785.     data[0] = (CARD32)XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  1786.     data[1] = (CARD32)time((long *)0);
  1787.     prop = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE),
  1788.       
  1789.     XChangeProperty(theDisp, mainW, prop, prop,
  1790.             32, PropModeReplace, (unsigned char *) data, 2);
  1791.     
  1792.     XMapWindow(theDisp,mainW);
  1793.       }
  1794.     }
  1795.  
  1796.     else {                            /* mainW already being used */
  1797.       CreateMainWindow(maingeom, basename);
  1798.       XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  1799.            | StructureNotifyMask | ButtonPressMask
  1800.            | EnterWindowMask | LeaveWindowMask );
  1801.  
  1802.       if (LocalCmap) {                /* AllocColors created local colormap */
  1803.     XSetWindowColormap(theDisp, mainW, LocalCmap);
  1804.       }
  1805.     }
  1806.  
  1807.     useroot = 0;
  1808.   }
  1809.  
  1810.  
  1811.  
  1812.   else if (dispMB.selected > 0 && (dispMB.selected <= RM_MAX+1)) {
  1813.     /* a 'root' mode */
  1814.     int ew, eh, regen;
  1815.  
  1816.     regen = 0;
  1817.     if (!useroot) {                  /* have to kill mainW, etc. */
  1818.       /* save current window position */
  1819.       haveoldinfo = 1;
  1820.       oldMainW = mainW;
  1821.       oldPerfect = perfect;
  1822.       oldNoglob = noglob;
  1823.       oldOwnCmap = owncmap;
  1824.  
  1825.       hadLocalCmap = LocalCmap;
  1826.       GetWindowPos(&oldXwa);
  1827.       if (!XGetNormalHints(theDisp, mainW, &oldHints)) oldHints.flags = 0;
  1828.       oldHints.x=oldXwa.x;  oldHints.y=oldXwa.y;  oldHints.flags|=USPosition;
  1829.  
  1830.       perfect = owncmap = 0;         /* can't do -perfect on a root window */
  1831.       noglob = 1;                    /* Phase 3 color alloc's a bad idea too */
  1832.       XUnmapWindow(theDisp, mainW);
  1833.       mainW = vrootW;
  1834.  
  1835.       if (!ctrlUp) {    /* make sure ctrl is up when going to 'root' mode */
  1836.     XWMHints xwmh;
  1837.     xwmh.initial_state = IconicState;
  1838.     xwmh.flags = StateHint;
  1839.     XSetWMHints(theDisp, ctrlW, &xwmh);
  1840.     CtrlBox(1);
  1841.       }
  1842.     }
  1843.       
  1844.     if (LocalCmap) {                 /* we *were* using -perfect */
  1845.       FreeAllColors();
  1846.       if (rwcolor) AllocRWColors();  else AllocColors();
  1847.       regen = 1;
  1848.     }
  1849.     
  1850.  
  1851.     useroot = 1;
  1852.     rootMode = dispMB.selected - 1;
  1853.     ew = eWIDE;  eh = eHIGH;
  1854.  
  1855.     RANGE(ew,1,maxWIDE);  RANGE(eh,1,maxHIGH);
  1856.  
  1857.     if (rootMode == RM_TILE || rootMode == RM_IMIRROR) {
  1858.       /* make picture size a divisor of the rootW size.  round down */
  1859.       i = (dispWIDE + ew-1) / ew;   ew = (dispWIDE + i-1) / i;
  1860.       i = (dispHIGH + eh-1) / eh;   eh = (dispHIGH + i-1) / i;
  1861.     }
  1862.  
  1863.     if (ew != eWIDE || eh != eHIGH) Resize(ew, eh);  /* changed size */
  1864.     else {
  1865.       /* didn't regen XImage.  If we were using LocalCmap we have to */
  1866.       if (regen) CreateXImage();                    
  1867.     }
  1868.  
  1869.     KillOldRootInfo();
  1870.     MakeRootPic();
  1871.     SetCursors(-1);
  1872.   }
  1873.  
  1874.   else {
  1875.     fprintf(stderr,"%s:  unknown dispMB value '%d' in HandleDispMode()\n",
  1876.         dispMB.selected);
  1877.   }
  1878. }
  1879.  
  1880. /************************************************************************/
  1881. /* following three rd_* functions swiped from xgraph, by David Harrison */
  1882. /************************************************************************/
  1883.  
  1884. /***********************************/
  1885. /* weikart, Mon Sep  2 18:26:36 1991; convert to lower-care for comparisons: */
  1886. char *lower_str(string)
  1887. char *string;
  1888. {
  1889.   char *p;
  1890.   for (p = string; *p != '\0'; p++)
  1891.     *p = tolower(*p);
  1892.   return string;
  1893. }
  1894.  
  1895.  
  1896. /***********************************/
  1897. int rd_int(name)
  1898. char *name;
  1899. {
  1900.   /* returns '1' if successful.  result in def_int */
  1901.  
  1902.   if (def_str) {
  1903.     if (sscanf(def_str, "%ld", &def_int) == 1) return 1;
  1904.     else {
  1905.       fprintf(stderr, "%s: couldn't read integer value for %s resource\n", 
  1906.           cmd,name);
  1907.       return 0;
  1908.     }
  1909.   }
  1910.   else return 0;
  1911.  
  1912. }
  1913.  
  1914. /***********************************/
  1915. int rd_str(name)
  1916. char *name;
  1917. {
  1918.   /* returns '1' if successful.  result in def_str */
  1919.   
  1920.   def_str = XGetDefault(theDisp, PROGNAME, name);
  1921.   if (def_str) return 1;
  1922.           else return 0;
  1923.  
  1924. }
  1925.  
  1926.  
  1927. /***********************************/
  1928. int rd_flag(name)
  1929. char *name;
  1930. {
  1931.   /* returns '1' if successful.  result in def_int */
  1932.   
  1933.   char buf[256];
  1934.  
  1935.   def_str = XGetDefault(theDisp, PROGNAME, name);
  1936.   if (def_str) {
  1937.     strcpy(buf, def_str);
  1938.     lower_str(buf);
  1939.  
  1940.     def_int = (strcmp(buf, "on")==0) || 
  1941.               (strcmp(buf, "1")==0) ||
  1942.           (strcmp(buf, "true")==0) ||
  1943.           (strcmp(buf, "yes")==0);
  1944.     return 1;
  1945.     }
  1946.  
  1947.   else return 0;
  1948. }
  1949.     
  1950.  
  1951.